﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Sgml.Matching;
using Engine.Dtd.Schema;
using System.Diagnostics;

namespace Engine.Sgml.Merging {
    internal sealed class InconsistentBlockExtractor {
        private CapturesIterator capturesIterator = new CapturesIterator();

        public IList<InconsistentBlock> Extract(IList<Capture> captures, Match match) {
            Guard.ArgumentNotNull(captures, "captures");
            Guard.ArgumentNotNull(match, "match");
            List<InconsistentBlock> blocks = new List<InconsistentBlock>();
            InconsistentBlock block = new InconsistentBlock(match.Ancestor);
            if (match.Model.CanRecur()) {
                for (int i = 0; i < captures.Count; i++) {
                    CaptureEntity entity = captures[i].Entity;
                    if (entity.IsIllegalElement) {
                        AddElement(entity.Element, ref block, blocks);
                        }
                    }
                }
            else
                for (int i = 0; i < captures.Count; i++) {
                    CaptureEntity entity = captures[i].Entity;
                    if (entity.IsIllegalElement) {
                        AddElement(entity.Element, ref block, blocks);
                        }
                    else if (entity.IsModelMatch && entity.Match != match && entity.Match.Type != AccordanceTypes.Inconsistent) {
                        capturesIterator.Reset(entity.Match);
                        while (capturesIterator.MoveNext()) {
                            Capture current = capturesIterator.Current;
                            entity = current.Entity;
                            if (current.Success) {
                                if (entity.IsElement)
                                    AddElement(entity.Element, ref block, blocks);
                                }
                            else if (entity.IsIllegalElement) {
                                AddElement(entity.Element, ref block, blocks);
                                }
                            }
                        }
                    }
            if (block.Count != 0)
                blocks.Add(block);
            return blocks;
            }

        private static void AddElement(SElement element, ref InconsistentBlock block, List<InconsistentBlock> blocks) {
            if (element.DefinedInScheme) {
                if (block.CanAddElement(element)) {
                    if (element.NodeType != SgmlNodeType.Comment && !ElementMatcher.IsCunstructedElement(element))
                        block.Add(element);
                    }
                else if (block.Count > 0) {
                    blocks.Add(block);
                    block = new InconsistentBlock(element.Parent);
                    if (block.CanAddElement(element) && !ElementMatcher.IsCunstructedElement(element))
                        block.Add(element);
                    }
                }
            else if (block.Count > 0) {
                blocks.Add(block);
                block = new InconsistentBlock(element.Parent);
                }
            }
        }
    }
